#include "z_string.h"
#include <stdio.h>
#include <locale.h>
#include <strings.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <wchar.h>
#include <ctype.h>

/*Function definition*/
/**********************
 * @param str Origin string
 * @return Encoded string
 * ********************/
static unsigned char hexchars[] = "0123456789ABCDEF";
static int php_htoi(char *s)
{
	int value;
	int c;

	c = ((unsigned char *)s)[0];
	if (isupper(c))
		c = tolower(c);
	value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;

	c = ((unsigned char *)s)[1];
	if (isupper(c))
		c = tolower(c);
	value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;

	return (value);
}
char *url_encode(char const *s, int len, int *new_length)
{
	unsigned char c;
	unsigned char *to, *start;
	unsigned char const *from, *end;
	
	from = (unsigned char *)s;
	end  = (unsigned char *)s + len;
	start = to = (unsigned char *) calloc(1, 3*len+1);

	while (from < end) 
	{
		c = *from++;

		if (c == ' ') 
		{
			*to++ = '+';
		} 
		else if ((c < '0' && c != '-' && c != '.') ||
				 (c < 'A' && c > '9') ||
				 (c > 'Z' && c < 'a' && c != '_') ||
				 (c > 'z')) 
		{
			to[0] = '%';
			to[1] = hexchars[c >> 4];
			to[2] = hexchars[c & 15];
			to += 3;
		}
		else 
		{
			*to++ = c;
		}
	}
	*to = 0;
	if (new_length) 
	{
		*new_length = to - start;
	}
	return (char *) start;
}


int url_decode(char *str, int len)
{
	char *dest = str;
	char *data = str;

	while (len--) 
	{
		if (*data == '+') 
		{
			*dest = ' ';
		}
		else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) && isxdigit((int) *(data + 2))) 
		{
			*dest = (char) php_htoi(data + 1);
			data += 2;
			len -= 2;
		} 
		else 
		{
			*dest = *data;
		}
		data++;
		dest++;
	}
	*dest = '\0';
	return dest - str;
}

char * multicat(char * end_str,char * str,...){
	va_list ap;
	va_start(ap,str);
	char * s = "\0";
	while (strcmp(s,end_str) != 0){
		strcat(str,s);
		s = va_arg(ap,char *);
	}
	va_end(ap);
	return str;
}//multicat()

void print_unicode(FILE * fd,char * str){
	char * p = get_unicode_from(str);
	if (p)
		fprintf(fd,"%lc",str2uni(p));
	else
		return;
	while ((p = get_unicode_from(p+6)) != NULL){
		fprintf(fd,"%lc",str2uni(p));
	}
}//print_unicode()

char * get_unicode_from(char * str){
	if(str == NULL) return NULL;
	char * p = str;
	while ((*p != '\0') && !is_unicode(p)) p++;
	if (*p == '\0')
		return NULL;
	return p;
}//get_unicode_from()

int is_unicode(char * p){
	if ( p == NULL) return 0;
	for (int i = 0; i < 6; ++i)
		if (*(p+i) == '\0') return 0;//Overflow detect
	int type = 0,flag = 0;
	if (*p == '\\' && *(p+1) == 'u')
		type = 1;
	else
	if (*p == '#' && *(p+1) == 'x')
		type = 2;
	else
	if (*p == '0' && *(p+1) == 'x')
		type = 3;
	else
		return 0;
	for (int i = 2; i < 6; ++i)//== isxdigit(char ch) in ctype.h
		if ((*(p+i) >= '0' && *(p+i) <= '9') ||
			(*(p+i) >= 'A' && *(p+i) <= 'F') ||
			(*(p+i) >= 'a' && *(p+i) <= 'f'))
				flag = type;
		else
				{flag = 0;break;}
	return flag;
}//is_unicode()

wchar_t str2uni(char * p){
	if(!is_unicode(p)) return 0;
	char unicode[7];
	strncpy(unicode,p,6);
	unicode[0] = '0';
	unicode[1] = 'x';
	unicode[6] = '\0';
	return (wchar_t)strtol(unicode,NULL,16);
}//str2uni()

int de_unicode( FILE * fd, char * str){
	wchar_t u_ch;
	unsigned int count = 0;
	char * begin = get_unicode_from(str);
	while((u_ch = str2uni(get_unicode_from(begin))) != 0){
		fprintf(fd,"%lc",u_ch);
		begin += 6;
		count++;
	}
	return count;
}//de_unicode()

char * int2str(int n){
	int r = 0,s = n;
	while (n){n = n/10;++r;}
	char * str = (char *)malloc((r+1) * sizeof(char));
	if (!str) exit(1);
	sprintf(str,"%d",s);
	str[r] = '\0';
	return str;
}//int2str()

